import { omitBy, isUndefined, Dictionary } from 'lodash';
import store from '@/assets/map/store.png';
import shop from '@/assets/map/shop.png';
import moment from 'moment';

interface Node {
  code: string;
  name: string;
  children?: Node[];
}

export const transformData = (data: Node[]) => {
  if (!data) return {};
  // console.time('下拉框数据计算时间');
  const processNode = (data: Node[]) =>
    data.reduce((cur: any, prev) => {
      cur[prev.code] = {
        name: prev.name,
      };
      if (prev.children) {
        cur[prev.code]['children'] = processNode(prev.children);
      }

      return cur;
    }, {});
  const result = processNode(data);
  // console.timeEnd('下拉框数据计算时间');

  return result;
};

/**
 * 从给定的选项中获取查询值。
 * @param options - 包含子选项的对象。
 * @param other - 可选的其他参数，用于获取更深层次的查询值。
 * @returns 返回查询值。
 */
export const getQuery = (options: { [x: string]: any }, ...other: any[]) => {
  let result = options;

  other.forEach(key => {
    result = result?.[key]?.children;
  });

  return Object.keys(result || {})[0];
};

/**
 * 将给定的节点数据转换为扁平化结构。
 * @param data 要转换的节点数组，每个节点包含代码和名称，以及可能的子节点。
 * @param name 用于作为根节点名称的字符串。
 * @returns 返回一个对象，其中键是节点代码的前缀，值是一个对象数组，每个对象包含代码和名称。
 */
// export const transformData = (data: Node[], name: string): FlattenedData => {
//   const result: any = {};

//   const processNode = (node: Node, prefix = '') => {
//     if (!result[prefix]) {
//       result[prefix] = [];
//     }
//     result[prefix].push({ code: node.code, name: node.name });

//     if (node.children && node.children.length > 0) {
//       node.children.forEach(child => {
//         processNode(child, node.code);
//       });
//     }
//   };

//   data.forEach(rootNode => {
//     processNode(rootNode, name);
//   });

//   return result;
// };

/**
 * 将节点数据扁平化为代码名称映射表
 * @param data 节点数组，每个节点包含代码(code)、名称(name)和子节点(children)属性
 * @returns 返回一个对象，键为节点代码，值为节点名称
 */
export const flattenToCodeNameMap = (data: any[]): { [key: string]: string } => {
  const result: any = {};

  const recursiveTraverse = (data: any[]) => {
    data.forEach(item => {
      const { code, name, children } = item;

      result[code] = name;
      if (children && children.length > 0) {
        recursiveTraverse(children);
      }
    });
  };

  recursiveTraverse(data);

  return result;
};

/**
 * 将给定数据转换为GeoJSON LineString格式的数组。
 * @param inputData 输入数据，包含主要位置的经纬度和一个存储位置数据的数组。
 * @param isReverse 指示是否反向处理坐标的布尔值。
 * @returns 返回一个包含GeoJSON Feature对象的数组，每个对象代表一个从主要位置到商店位置的线段。
 */
export const convertToGeoJSONLineStrings = (inputData: any, isReverse: boolean): any[] => {
  const { lon: mainLong, lat: mainLat } = inputData.chosenStoreData;
  const features: any[] = [];

  const data = inputData?.otherStoreData;

  data?.forEach((store: { lon: any; lat: any }) => {
    const { lon, lat } = store;

    const coordinates: [number, number][] = [
      [mainLong, mainLat],
      [lon, lat],
    ];

    features.push({
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: isReverse ? coordinates : coordinates.reverse(),
      },
    });
  });

  return features;
};

/**
 * Returns SW/NE latitude/longitude bounds of specified geohash.
 * @param   {string} geohash - Cell that bounds are required of.
 * @returns {{sw: {lat: number, lng: number}, ne: {lat: number, lng: number}}}
 * @throws  Invalid geohash.
 */
export const bounds = (
  geohash: string,
): {
  sw: { lat: number; lng: number };
  ne: { lat: number; lng: number };
} => {
  if (geohash.length == 0) throw new Error('Invalid geohash');
  const base32 = '0123456789bcdefghjkmnpqrstuvwxyz';

  geohash = geohash.toLowerCase();

  let evenBit = true;
  let latMin = -90,
    latMax = 90;
  let lonMin = -180,
    lonMax = 180;

  for (let i = 0; i < geohash.length; i++) {
    const chr = geohash.charAt(i);
    const idx = base32.indexOf(chr);
    if (idx == -1) throw new Error('Invalid geohash');

    for (let n = 4; n >= 0; n--) {
      const bitN = (idx >> n) & 1;
      if (evenBit) {
        // longitude
        const lonMid = (lonMin + lonMax) / 2;
        if (bitN == 1) {
          lonMin = lonMid;
        } else {
          lonMax = lonMid;
        }
      } else {
        // latitude
        const latMid = (latMin + latMax) / 2;
        if (bitN == 1) {
          latMin = latMid;
        } else {
          latMax = latMid;
        }
      }
      evenBit = !evenBit;
    }
  }

  return {
    sw: { lat: latMin, lng: lonMin },
    ne: { lat: latMax, lng: lonMax },
  };
};

// export const mapper = ['免保', '保修', '召回专案', '自主到店', '首保', '定期保养'];
export const mapper = [
  '普通维修',
  '定保',
  '保险',
  '免费保养',
  '保修',
  '专案',
  '召回',
  '服务活动',
  'PDI',
];

export const store_icon = {
  type: 'image',
  image: store,
  size: [40, 40],
  anchor: 'center',
};

export const shop_icon = {
  type: 'image',
  image: shop,
  size: [40, 40],
  anchor: 'center',
};

/**
 * 定义一个泛型函数并导出，可以处理数据并返回一个 Promise
 *
 * @param query - 一个对象，将被处理和传递给 action 函数
 * @param action - 一个函数，它接受一个 Partial<T> 类型的参数，并返回一个 Promise
 * @returns 调用 action 函数并返回它的 Promise
 */
export const withProcessedData = <T extends object>(
  query: T,
  action: (arg0: Dictionary<T>) => Promise<any>,
) => action(omitBy(query, isUndefined));

/**
 * 查找嵌套数据结构中的目标代码的路径
 *
 * @param data 要搜索的数据，通常是一个嵌套的对象数组
 * @param targetCode 要查找的目标代码
 * @param path （可选）当前搜索路径，默认为空数组
 * @returns 找到目标代码时，返回包含目标代码路径的数组；未找到时，返回 g[]
 */
export function getPath(data: any[], targetCode: any, path = []) {
  for (let i = 0; i < data.length; i++) {
    const current = data[i];
    path.push(current.code);

    if (current.children && current.children.some(child => child.code === targetCode)) {
      path.push(current.children.find(child => child.code === targetCode).code);
      return path;
    } else if (current.children) {
      let result = getPath(current.children, targetCode, [...path]);
      if (result) {
        return result;
      }
    }

    path.pop();
  }

  return null;
}

export const deduplicateByCode = (arr: any[], key: string | number) => {
  const codeMap = new Map();
  return arr.filter(item => {
    if (!codeMap.has(item[key])) {
      codeMap.set(item[key], true);
      return true;
    }
    return false;
  });
};

/**
 * 格式化数值并添加后缀
 * 如果值为0，则返回"0"加上后缀
 * 如果值为空，则返回"-"
 * 否则，将值转换为字符串并添加后缀
 * @param value - 要格式化的值
 * @param company - 后缀，默认为空字符串
 * @returns 格式化后的字符串
 */
export const formatValue = (value: number, company = '') => {
  if (value === 0) {
    return '0' + company;
  }
  if (!value) {
    return '-';
  }
  // 将所有其他值转换为字符串
  return String(value) + company;
};

export const getDateRange = (date: string) => {
  const inputDate = moment(new Date(date)); // 解析传入的日期

  const oneMonthAgo = inputDate.clone().subtract(1, 'months'); // 计算一个月前的日期
  return ` ${oneMonthAgo.format('YYYY.MM.DD')} ~ ${inputDate.format('YYYY.MM.DD')}`;
};

export const getLastMonthRange = (date: string) => {
  const inputDate = moment(new Date(date)); // 解析传入的日期

  return inputDate.subtract(1, 'month').format('YYYY.MM');
  // 获取上个月的月初
  // const startOfLastMonth = inputDate.clone().subtract(1, 'months').startOf('month');
  // // 获取上个月的月末
  // const endOfLastMonth = inputDate.clone().subtract(1, 'months').endOf('month');

  // return `${startOfLastMonth.format('YYYY.MM.DD')} ~ ${endOfLastMonth.format('YYYY.MM.DD')}`;
};

export const sortByKey = (arr: any[], key: string, asc: boolean = false) => {
  if (!arr) return [];

  if (asc) {
    return arr.sort((a, b) => a[key] - b[key]);
  } else {
    return arr.sort((a, b) => b[key] - a[key]);
  }
  // return arr.sort((a, b) => (asc ? a[key] - b[key] : b[key] - a[key]));
};

export const getClosestMultipleOfFour = (num: number): number => {
  return Math.ceil(num / 4) * 4;
};

export const divideValueIntoIntervals = (value: number) => {
  const step = value / 4;
  const intervals = [];
  for (let i = 0; i < 4; i++) {
    intervals.push([i * step, (i + 1) * step]);
  }
  return intervals;
};
export const findIntervalIndex = (value, intervals) => {
  for (let i = 0; i < intervals.length; i++) {
    const [start, end] = intervals[i];
    if (value >= start && value < end) {
      return i; // 返回区间的下标
    }
  }
  return 3; // 如果不在任何区间内
};

export const formatDate = (value: string, type: any = '') => {
  switch (type) {
    case 'year':
      return value.slice(0, 7).replace(/-/g, '/');
    default:
      return value.slice(5, 10).replace(/-/g, '/');
  }
};

export const content = (data: { name: string; vehicleCount: number; nearestStoreName: string }) => `
  <div class="title">${data.name}</div>
  <div class="item">活跃用户数<span class="text">${formatValue(data.vehicleCount)}</span></div>
  <div class="item">最近专营店<span class="text">${data.nearestStoreName}</span></div>
`;

export const colors = [
  '#1890ff',
  '#4dc9c5',
  '#ff922e',
  '#ff594c',
  '#fad337',
  '#4dcb73',
  '#ff8b9f',
  '#a470eb',
  '#82d5f7',
  // 其他颜色...
  '#cd5c5c',
  '#ffa500',
  '#40e0d0',
  '#1e90ff',
  '#ff6347',
  '#7b68ee',
  '#00fa9a',
  '#ffd700',
  '#6699FF',
  '#ff6666',
  '#3cb371',
  '#b8860b',
  '#30e0e0',
];

export const isCategory = (arr) => (arr || []).find(item => item.category === '0')
